﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Xml.Linq;

namespace devtm.Editor.Configuration.Merge
{

    public class ConfigurationCompareHelper
    {

        public DiffListe DiffListe;

        public ConfigurationCompareHelper(ElementSection elementSection, System.Configuration.Configuration configuration)
        {

            this.DiffListe = new DiffListe();

            // Comparaison de A -> B
            foreach (ElementSection item in elementSection.Items)
                if (item.ConfigurationElement is ConfigurationSection || item.Group != null)
                    CompareAllReadyLoaded(item, configuration);
            

            // Comparaison de B -> A
            foreach (string i in configuration.SectionGroups.Keys)
            {
                var j = Datas.Lazy.GetObject(() => configuration.GetSectionGroup(i));

                if (j.IsDeclared)
                    CompareConfigurationGroup(j, elementSection);

            }


            // Comparaison de B -> A
            foreach (string i in configuration.Sections.Keys)
            {
                var k = Datas.Lazy.GetObject(() => configuration.Sections[i]);

                if (k.ElementInformation.IsPresent)
                    if (!CompareConfiguration(k, elementSection))
                        DiffListe.Add(DiffItem.Create(null, k));
                    
            }

        }

        private bool CompareConfiguration(ConfigurationSection k, ElementSection elementSection)
        {

            string n1 = k.SectionInformation.Name;

            foreach (ElementSection item in elementSection.Items)

                if (item.ConfigurationElement is ConfigurationSection || item.Group != null)
                {
                    ElementSection i = FindElementSection(n1, item);
                    if (i != null)
                        return true;

                }

            return false;
        }

        private ElementSection FindElementSection(string n1, ElementSection item)
        {

            if (item.ConfigurationElement != null)
            {
                var m = (item.ConfigurationElement as ConfigurationSection);

                if (!m.ElementInformation.IsPresent)
                    return null;

                if (m.SectionInformation.Name == n1)
                    return item;

            }
            else if (item.Group != null && !item.Group.IsDeclared)
                return null;
            

            foreach (ElementSection j in item.Items)

                if (j.ConfigurationElement is ConfigurationSection || j.Group != null)
                {
                    ElementSection i = FindElementSection(n1, j);
                    
                    if (i != null)

                        return j;
                    
                }

            return null;
        }

        private void CompareConfigurationGroup(ConfigurationSectionGroup configurationSectionGroup, ElementSection elementSection)
        {

            foreach (string i in configurationSectionGroup.SectionGroups.Keys)
            {

                var j = Datas.Lazy.GetObject(() => configurationSectionGroup.SectionGroups[i]);

                if (j.IsDeclared)

                    CompareConfigurationGroup(j, elementSection);

            }

            foreach (string i in configurationSectionGroup.Sections.Keys)
            {

                var k = Datas.Lazy.GetObject(() => configurationSectionGroup.Sections[i]);

                if (k.ElementInformation.IsPresent)

                    CompareConfiguration(k, elementSection);
            }

        }

        internal void CompareAllReadyLoaded(ElementSection elementSection, System.Configuration.Configuration configuration)
        {


            if (elementSection.ConfigurationElement is ConfigurationSection)
            {

                var section = (elementSection.ConfigurationElement as ConfigurationSection);

                if (section.ElementInformation.IsPresent)
                {

                    string xmlStr2 = string.Empty;

                    Datas.Lazy.Resolver.LastResolve.Clear();
                    ConfigurationSection s = null;
                    try
                    {
                        s = Datas.Lazy.GetObject(() => configuration.GetSection(section.SectionInformation.Name));

                        if (s == null)
                        {
                            DiffListe.Add(DiffItem.Create(elementSection, s));
                            return;
                        }

                        xmlStr2 = s.SectionInformation.GetRawXml();

                        if (string.IsNullOrEmpty(xmlStr2))
                        {
                            DiffListe.Add(DiffItem.Create(elementSection, s));
                            return;
                        }

                    }
                    catch (Exception)
                    {
                        DiffListe.Add(DiffItem.Create(elementSection, s));
                    }

                    // verifier la forme
                    var Xml1 = elementSection.RawXml;
                    var Xml2 = XElement.Parse(xmlStr2);

                    if (!CompareXml(Xml1, Xml2))
                        DiffListe.Add(DiffItem.Create(elementSection, s));

                }
                else
                    return;

            }
            else
            {
                if (elementSection.Group.IsDeclared)
                {

                    foreach (ElementSection item in elementSection.Items)
                        if (item.ConfigurationElement is ConfigurationSection || item.Group != null)
                            CompareAllReadyLoaded(item, configuration);

                }
            
            }


        
        }

        private static bool CompareXml(XElement Xml1, XElement Xml2)
        {

            var i1 = Xml1.ToString(SaveOptions.DisableFormatting);
            var i2 = Xml2.ToString(SaveOptions.DisableFormatting);

            return String.Equals(i1, i2); ;

        }

    }
}
